<script setup lang="ts">
import VDialog from "@/components/VDialog/VDialog.vue";
import { useSubmissionHook } from "./utils/hook";
import { computed, nextTick, reactive, ref, watch } from "vue";
import {
  AddSubmissionCommand,
  SubmissionPageResponse,
  UpdateSubmissionCommand,
  addSubmissionApi,
  updateSubmissionApi,
  uploadToQiniuApi
} from "@/api/performance/submission";
import { useUserStoreHook } from "@/store/modules/user";
import { ElMessage, FormInstance, FormRules } from "element-plus";
import { getAllUsersSimpleApi, type UserSimpleDTO } from "@/api/system/user";
const { categoryData } = useSubmissionHook();
const userStore = useUserStoreHook();

// 工作量计分办法映射
const scoringRulesMap: Record<string, string> = {
  "论文和学术报告": `1 区 SCI 论文 1 篇记 1000 分，2 区 SCI 论文 1 篇记 700 分，3 区 SCI 论文 1 篇记 400 分，4 区 SCI 论文或 EI 期刊论文 1 篇记 300 分，北大核心论文 1 篇记 200 分，普刊、教改论文和会议论文 1 篇记 100 分。每年最多 5 篇论文可记积分。

参加省部级以上学术会议并做报告 1 次记 60 分，参加校级学术会议并做报告 1 次记 30 分。每年累计不超过 300 分。

论文或学术报告均应以中国民用航空飞行学院为第一署名单位，且以第一作者或通讯作者发表。同一篇论文只计 1 次，如有本学院合作作者，自行协商分配积分。`,
  "科研项目": `国家自然科学基金面上项目 1 项记 6000 分，国家自然科学基金青年项目 1 项记 3000 分，国家自然科学基金重点项目的子课题 1 项记 2000 分，省部级重点基金项目 1 项记 2000 分，省部级基金项目 1 项记 1000 分，厅局级项目 1 项记 500 分，校级重点项目 1 项记 300 分，校级面上项目 1 项记 200 分，校级青年项目 1 项记 100 分，横向项目到账经费每 1 万记 10 分，每一年度横向项目不超过 2000 分。

以上积分均是作为项目负责人得分，并且以中国民用航空飞行学院为第一单位。如有本学院合作者，自行协商分配积分。

项目的级别认定按照学校相关文件执行，同一项目只记 1 次,可以在项目计划周期内分配积分到不同年度。`,
  "教研项目": `国家级教研项目 1 项记 3000 分，省部级教研项目 1 项记 1500 分，校级教研项目 1 项记 200 分。

以上积分均是作为项目负责人得分，并且以中国民用航空飞行学院为第一单位，如有本学院合作者，自行协商分配积分。`,
  "其他科研教研成果": `国家级一等奖 1 项记 3000 分、二等奖 1 项记 1500 分、三等奖 1 项记 1000 分；省部级一等奖 1 项记 800 分、二等奖 1 项记 600 分、三等奖 1 项记 400 分；校级获奖 1 项记 100 分。

授权 1 项发明专利记 800 分，授权 1 项实用新型专利或软件著作权记 100 分。

以上积分均为排名第一得分，并且以中国民用航空飞行学院为第一单位，如有本学院合作者，自行协商分配积分。

出版国家级或省部级学术著作(专著、教材、译著等)1 部记 3000 分，具体分数由参编人员自行协商分配；出版校级学术著作(专著、教材、译著等)1 部记 1500 分，具体分数由参编人员自行协商分配。`,
  "学术兼职": `国家自然基金委评审专家，如果有评审的年度，当年记 200 分；SCI、EI、核心期刊的主编、副主编、编委在任期内，每一年记 100 分；国家级、省部级学术协会的委员及以上，每年记 100 分；每年累计不超过 200 分。`,
  "学科竞赛": `指导理学院学生参加学科竞赛获国家级一等奖 1 项记 1000 分、二等奖 1 项记 800 分、三等奖 1 项记 600 分；获省部级一等奖 1 项记 400 分、二等奖 1 项记 200 分、三等奖 1 项记 100 分。每年最多 4 项获奖可记积分。

在以上育人工作量积分中，指导学生工作如果没有理学院学生，均按 50%积分。学科竞赛获奖参照高校学科竞赛排行榜榜单，非榜单的获奖均按 50%积分。`,
  "学科竞赛组织与培训": `参与学科竞赛的组织、培训和指导，工作量达 16 学时以上记 1 分。`,
  "科研论文": `指导理学院学生发表科研论文 1 篇，学生第一作者记 200 分、学生参与记 100 分，每年累计不超过 200 分。

在以上育人工作量积分中，指导学生工作如果没有理学院学生，均按 50%积分。`,
  "育人工作量-科研项目": `指导理学院学生参与科研项目记 50 分，每年累计不超过 100 分。

在以上育人工作量积分中，指导学生工作如果没有理学院学生，均按 50%积分。`,
  "科研项目申报": `指导理学院学生成功完成申报省部级及以上的科研项目 1 项记 100 分。

在以上育人工作量积分中，指导学生工作如果没有理学院学生，均按 50%积分。`,
  "专利与学术著作": `指导理学院的学生参与专利、获奖等申报工作，参与编写学术著作 (专著、教材、译著等)1 项记 100 分，每年累计不超过 200 分。

在以上育人工作量积分中，指导学生工作如果没有理学院学生，均按 50%积分。`,
  "毕业论文指导": `指导理学院毕业生 1 名，完成毕业论文记 50 分，每年累计不超过 400 分。

在以上育人工作量积分中，指导学生工作如果没有理学院学生，均按 50%积分。`,
  "硕士研究生指导": `指导理学院硕士研究生 1 名，完成相关开题工作记 50 分，完成毕业论文记 100 分，每年累计不超过 500 分。

在以上育人工作量积分中，指导学生工作如果没有理学院学生，均按 50%积分。`,
  "学术会议指导": `指导理学院学生参加国内外重要学术会议并作报告 1 次记 100 分，每年累计不超过 200 分。

在以上育人工作量积分中，指导学生工作如果没有理学院学生，均按 50%积分。`,
  "新教师指导": `指导新教师 1 名，并且完成相关指导工作记 100 分；指导新教师参加省级竞赛并获成功参赛奖 1 项记 100 分，获省级奖励 1 项记 200 分、获国家级奖励 1 项记 300 分，每年累计不超过 300 分。`,
  "服务工作量": `深度参与数学、应用统计、大数据技术与工程硕士点建设，并取得阶段性成果，记 100 分，每年累计不超过 300 分。

深度参与信息与计算科学、数据科学与大数据专业建设，并取得阶段性成果，记 100 分；每年修订人才培养方案，记 200 分。每年累计不超过 300 分。

举办国家级学术或教研会议，覆盖校外人员 10 人以上或重量级专家参会，扩大学院的影响力，记 200 分；举办省级学术或教研会议，覆盖校外人员 5 人以上或重量级专家参会，扩大学院的影响力，记 100 分；邀请知名专家到校开展学术报告，记 50 分。每年累计不超过 300 分。

深度参与实验实训基地建设，并取得阶段性成果，每年累计不超过 2 分。

参与国家级实验室或平台管理，并取得阶段性成果，每年累计不超过 200 分。

参与省级实验室或平台管理，并取得阶段性成果，每年累计不超过 150 分。

参与校级实验室或平台管理，并取得阶段性成果，每年累计不超过 100 分。

实验室的设备管理工作，管理 1 间实验室，且管理实验器材件数大于等于 40 件或实验器材资产大于等于 100 万元，有明确的责任人、资产卡片且当年无安全事故，每年记 100 分。

固定资产超过 2000 万(含)的实验室按照国家级实验室处理；固定资产在 1000 万(含)至 2000 万的实验室按照省级实验室处理；教学实验室按照校级实验室处理，不重复记录。每年仅一项实验室建设或管理参与记分，每年累计不超过 200 分；有建设期的实验室可以按照计划积分，但不能超过单项最高积分。

负责国家级一流课程建设，具有阶段性成果，记 500 分；参与建设 1 门理学院的国家级一流课程(排名前 5)，具有阶段性成果，记 200 分。

负责省级一流课程建设，具有阶段性成果，记 300 分；参与建设 1 门理学院的省级一流课程(排名前 5)，具有阶段性成果，记 150 分。

负责校级一流课程建设，具有阶段性成果，记 200 分；参与建设 1 门理学院的校级一流课程(排名前 5)，具有阶段性成果，记 80 分。

负责 1 门课程的课程建设，具有阶段性成果，记 100 分；参与建设 1 门理学院课程的建设，具有阶段性成果，记 50 分。

阶段性成果一般指上线全网公开的课程资源建设或学院统一安排课程大纲修订、或校级以上一流课程建设或相当课程建设荣誉等。每年不超过两项课程建设参与记分，每年累计不超过 300 分；有建设期的课程可以按照计划积分，但不能超过单项最高积分。

对于承担党政管理工作的专业技术人员，如果按照专业技术岗位考核，其党政管理工作量积分标准如下：在顺利完成全年党政管理工作任务的条件下，院长记 500 分，副院长记 400 分，办公室主任记 300 分，办公室人员(含坐班制度的借调)记 250 分，系、教研室主任记 200 分，副主任记 150 分，党支部书记记 100 分，支部委员记 50 分，纪委委员记 50 分，督导组成员记 100 分，班导师记 100 分，工会委员以及工会小组成员记 50 分。对于承担了学院服务事项的教师，根据服务事项清单实施办法给与相应绩效分数。本项积分最高 500 分。

提供有社会影响力的社会服务工作，有相关的业绩或证书，记 100 分，每年累计不超过 100 分。

为理学院创收(常规工作以外的其他工作，并列入学院创收)，每 2 万元计 100 分。

服务理学院的相关重大事项等，具体工作量和积分由被考核人提出，各系室和基层组织统一上报学院绩效工作领导小组，形成方案后提交党委会审定，原则上不超过 100 分。`
};

// 获取当前子类别的计分办法
const currentScoringRule = computed(() => {
  const subCategory = formData.subCategory;
  const mainCategory = formData.mainCategory;
  if (!subCategory) return "";
  
  // 对于育人工作量下的科研项目，使用特殊key
  if (mainCategory === "育人工作量" && subCategory === "科研项目") {
    return scoringRulesMap["育人工作量-科研项目"] || "";
  }
  
  // 对于服务工作量，使用主类别作为key
  if (mainCategory === "服务工作量") {
    return scoringRulesMap["服务工作量"] || "";
  }
  
  return scoringRulesMap[subCategory] || "";
});

interface Props {
  type: "add" | "update";
  modelValue: boolean;
  row?: SubmissionPageResponse;
}

const props = defineProps<Props>();
const emits = defineEmits<{
  (e: "update:modelValue", v: boolean): void;
  (e: "success"): void;
}>();

const visible = computed({
  get: () => props.modelValue,
  set(v) {
    emits("update:modelValue", v);
  }
});

const formData = reactive<AddSubmissionCommand | UpdateSubmissionCommand>({
  id: 0,
  assessmentYear: new Date().getFullYear(),
  mainCategory: "",
  subCategory: "",
  itemCategory: "",
  title: "",
  userReportedScore: 0,
  status: "DRAFT",
  currentAuditLevel: 0,
  rejectionReason: "",
  fileList: "",
  detailsJson: "",
  allocationDetails: "",
});

// 额外的动态表单与上传状态
const detailsForm = reactive<Record<string, any>>({});
const uploadedUrls = ref<string[]>([]);
const uploadFileList = ref<any[]>([]);

// 多人参与分配
const isMultiProject = ref<boolean>(false);
// 分配列表（每项：用户与分数）
type AllocationItem = { userId?: number; userLabel?: string; score?: number; fixed?: boolean };
const allocationList = reactive<AllocationItem[]>([]);
// 分配依据（共享一份材料给所有分配）
const allocationEvidenceUploadFiles = ref<any[]>([]);
const allocationEvidenceUrls = ref<string[]>([]);
// 全量简要用户与筛选结果
const allUsers = ref<UserSimpleDTO[]>([]);
const userOptions = ref<UserSimpleDTO[]>([]);

const currentUserId = computed(() => userStore.currentUserInfo?.userId as number | undefined);
const currentUserLabel = computed(() => {
  const uid = currentUserId.value;
  if (!uid) return undefined;
  const hit = allUsers.value.find(u => u.userId === uid);
  if (hit) return getUserLabel(hit);
  const info: any = userStore.currentUserInfo;
  const name = info?.nickname || info?.username || info?.realName || "";
  const dept = info?.deptName || "";
  if (!name) return undefined;
  return dept ? `${name}（${dept}）` : name;
});

function ensureCurrentUserOption() {
  const uid = currentUserId.value;
  if (!uid) return;
  if (!allUsers.value.some(u => u.userId === uid)) {
    const info: any = userStore.currentUserInfo;
    const fallback: UserSimpleDTO = {
      userId: uid,
      nickname: info?.nickname || info?.username || info?.realName || "",
      deptName: info?.deptName || ""
    } as UserSimpleDTO;
    allUsers.value = [fallback, ...allUsers.value];
  }
  if (!userOptions.value.some(u => u.userId === uid)) {
    const refUser = allUsers.value.find(u => u.userId === uid);
    if (refUser) {
      userOptions.value = [refUser, ...userOptions.value];
    }
  }
}

function ensureLeaderRow() {
  const uid = currentUserId.value;
  if (!uid) return;
  ensureCurrentUserOption();
  let label = currentUserLabel.value;
  if (!label) {
    const info: any = userStore.currentUserInfo;
    const name = info?.nickname || info?.username || info?.realName || "";
    const dept = info?.deptName || "";
    label = dept ? `${name}（${dept}）` : name || undefined;
  }
  if (!label) label = "";

  let leader: AllocationItem | undefined;
  const existingIdx = allocationList.findIndex(item => item.userId === uid);
  if (existingIdx >= 0) {
    leader = allocationList.splice(existingIdx, 1)[0];
  }
  if (!leader) {
    leader = { userId: uid, userLabel: label, score: undefined };
  }
  leader.userId = uid;
  leader.userLabel = label;
  leader.fixed = true;
  allocationList.unshift(leader);

  allocationList.forEach((item, index) => {
    if (index === 0) {
      item.userId = uid;
      item.userLabel = label;
      item.fixed = true;
    } else {
      if (item.userId === uid) {
        item.userId = undefined;
        item.userLabel = undefined;
      }
      item.fixed = false;
    }
  });
}

async function fetchAllUsersSimple() {
  try {
    const { data } = await getAllUsersSimpleApi();
    allUsers.value = data || [];
    userOptions.value = allUsers.value;
    ensureCurrentUserOption();
    if (isMultiProject.value) {
      ensureLeaderRow();
    }
  } catch (e) {
    console.error(e);
  }
}

function remoteSearchUsers(query: string) {
  const q = (query || "").trim();
  if (!q) {
    userOptions.value = allUsers.value;
    return;
  }
  const lower = q.toLowerCase();
  userOptions.value = allUsers.value.filter(u =>
    (u.nickname || "").toLowerCase().includes(lower) ||
    (u.deptName || "").toLowerCase().includes(lower)
  );
}

function getUserLabel(u: UserSimpleDTO) {
  const name = u.nickname || "";
  const dept = u.deptName || "";
  return dept ? `${name}（${dept}）` : name;
}

function addAllocationRow() {
  if (!allocationList.length) {
    ensureLeaderRow();
    return;
  }
  allocationList.push({ userId: undefined, userLabel: undefined, score: undefined, fixed: false });
}
function removeAllocationRow(idx: number) {
  if (allocationList[idx]?.fixed) {
    ElMessage.warning("项目负责人不可删除");
    return;
  }
  allocationList.splice(idx, 1);
}

// 计算属性用于联动下拉框
const mainCategoryOptions = computed(() => {
  return categoryData.map(item => ({
    value: item.value,
    label: item.label
  }));
});

const subCategoryOptions = computed(() => {
  if (formData.mainCategory) {
    const mainCategory = categoryData.find(item => item.value === formData.mainCategory);
    if (mainCategory && mainCategory.children) {
      return mainCategory.children.map(item => ({
        value: item.value,
        label: item.label
      }));
    }
  }
  return [];
});

const itemCategoryOptions = computed(() => {
  if (formData.mainCategory && formData.subCategory) {
    const mainCategory = categoryData.find(item => item.value === formData.mainCategory);
    if (mainCategory && mainCategory.children) {
      const subCategory = mainCategory.children.find(item => item.value === formData.subCategory);
      if (subCategory && subCategory.children) {
        return subCategory.children.map(item => ({
          value: item.value,
          label: item.label
        }));
      }
    }
  }
  return [];
});

// 监听主类别变化，当选择"其他工作量"时自动选择子类别和项目类别为"其他"
watch(
  () => formData.mainCategory,
  (newVal) => {
    if (newVal === "其他工作量") {
      // 延迟设置，确保下拉选项已更新
      setTimeout(() => {
        formData.subCategory = "其他";
        // 再延迟设置项目类别
        setTimeout(() => {
          formData.itemCategory = "其他";
        }, 100);
      }, 100);
    }
  }
);

// 根据子类别/项目类别生成动态字段
type Field = { key: string; label: string; type?: "input" | "number" | "date" | "textarea" | "switch" };
const dynamicFields = computed<Field[]>(() => {
  const sub = (formData.subCategory || "").trim();
  const item = (formData.itemCategory || "").trim();
  if (!sub || !item) return [];

  // 当选择"其他工作量"时的特殊处理
  if (formData.mainCategory === "其他工作量") {
    return [
      { key: "workContent", label: "工作内容描述", type: "textarea" },
      { key: "startDate", label: "开始日期", type: "date" },
      { key: "endDate", label: "结束日期", type: "date" },
      { key: "workResult", label: "工作成果", type: "textarea" },
      { key: "remark", label: "备注", type: "textarea" }
    ];
  }

  // 论文和学术报告
  if (sub === "论文和学术报告") {
    return [
      { key: "paperTitle", label: "论文/报告题目" },
      { key: "journalOrConf", label: "期刊/会议名称" },
      { key: "partition", label: "分区/类别" },
      { key: "publishDate", label: "发表/报告日期", type: "date" },
      { key: "isFirstAffiliation", label: "第一署名单位为中飞行院", type: "switch" },
      { key: "isFirstOrCorresponding", label: "是否第一作者/通讯作者", type: "switch" },
      { key: "authors", label: "作者(按顺序)" }
    ];
  }
  // 科研项目/教研项目
  if (sub === "科研项目" || sub === "教研项目") {
    // 横向项目到账经费单独字段
    if (item.includes("横向项目到账经费")) {
      return [
        { key: "projectName", label: "项目名称" },
        { key: "amountWan", label: "到账经费(万元)", type: "number" },
        { key: "year", label: "到账年度" },
        { key: "isPI", label: "是否项目负责人", type: "switch" },
        { key: "firstUnit", label: "第一单位为中飞院", type: "switch" }
      ];
    }
    return [
      { key: "projectName", label: "项目名称" },
      { key: "projectLevel", label: "项目级别/类别" },
      { key: "projectNo", label: "立项编号" },
      { key: "startDate", label: "开始日期", type: "date" },
      { key: "endDate", label: "结束日期", type: "date" },
      { key: "isPI", label: "是否项目负责人", type: "switch" },
      { key: "firstUnit", label: "第一单位为中飞院", type: "switch" }
    ];
  }
  // 其他科研教研成果
  if (sub === "其他科研教研成果") {
    if (item.includes("专利")) {
      return [
        { key: "patentTitle", label: "专利名称" },
        { key: "patentType", label: "专利类型" },
        { key: "authNo", label: "授权号" },
        { key: "authDate", label: "授权日期", type: "date" },
        { key: "isFirstRank", label: "是否排名第一", type: "switch" },
        { key: "firstUnit", label: "第一单位为中飞院", type: "switch" }
      ];
    }
    if (item.includes("著作")) {
      return [
        { key: "bookTitle", label: "著作名称" },
        { key: "isbn", label: "ISBN/出版编号" },
        { key: "publisher", label: "出版社/出版单位" },
        { key: "pubDate", label: "出版日期", type: "date" }
      ];
    }
    if (item.includes("获奖") || item.includes("奖")) {
      return [
        { key: "awardName", label: "奖项名称" },
        { key: "awardLevel", label: "级别/等级" },
        { key: "awardingBody", label: "授奖单位" },
        { key: "awardDate", label: "获奖日期", type: "date" }
      ];
    }
  }
  // 学术兼职
  if (sub === "学术兼职") {
    return [
      { key: "position", label: "兼职职务" },
      { key: "organization", label: "机构/期刊/协会" },
      { key: "year", label: "年度" }
    ];
  }
  // 育人工作量
  if (formData.mainCategory === "育人工作量") {
    if (sub === "学科竞赛") {
      return [
        { key: "competitionName", label: "竞赛名称" },
        { key: "award", label: "获奖等级" },
        { key: "awardDate", label: "获奖日期", type: "date" },
        { key: "studentNames", label: "学生姓名" }
      ];
    }
    if (sub === "学科竞赛组织与培训") {
      return [
        { key: "activityName", label: "活动名称" },
        { key: "hours", label: "工作量(学时)", type: "number" },
        { key: "date", label: "完成日期", type: "date" }
      ];
    }
    if (sub === "科研论文") {
      return [
        { key: "paperTitle", label: "论文题目" },
        { key: "journal", label: "期刊/会议" },
        { key: "isStudentFirst", label: "学生第一作者", type: "switch" },
        { key: "publishDate", label: "发表日期", type: "date" }
      ];
    }
    if (sub === "科研项目") {
      return [
        { key: "projectName", label: "项目名称" },
        { key: "participation", label: "参与情况/内容" },
        { key: "date", label: "参与日期", type: "date" }
      ];
    }
    if (sub === "科研项目申报") {
      return [
        { key: "projectName", label: "项目名称" },
        { key: "level", label: "级别" },
        { key: "date", label: "申报/立项日期", type: "date" }
      ];
    }
    if (sub === "专利与学术著作") {
      return [
        { key: "title", label: "名称" },
        { key: "type", label: "类型(专利/著作/获奖)" },
        { key: "date", label: "完成日期", type: "date" }
      ];
    }
    if (sub === "毕业论文指导") {
      return [
        { key: "studentName", label: "学生姓名" },
        { key: "topic", label: "论文题目" },
        { key: "finishDate", label: "完成日期", type: "date" }
      ];
    }
    if (sub === "硕士研究生指导") {
      return [
        { key: "studentName", label: "学生姓名" },
        { key: "stage", label: "阶段(开题/毕业)" },
        { key: "date", label: "完成日期", type: "date" }
      ];
    }
    if (sub === "学术会议指导") {
      return [
        { key: "conference", label: "会议名称" },
        { key: "reportTitle", label: "报告题目" },
        { key: "date", label: "报告日期", type: "date" }
      ];
    }
    if (sub === "新教师指导") {
      return [
        { key: "teacherName", label: "新教师姓名" },
        { key: "content", label: "指导内容" },
        { key: "date", label: "完成日期", type: "date" }
      ];
    }
  }
  // 服务工作量（部分通用）
  if (formData.mainCategory === "服务工作量") {
    return [
      { key: "serviceName", label: "服务事项/建设名称" },
      { key: "stageResult", label: "阶段性成果说明", type: "textarea" },
      { key: "date", label: "完成日期", type: "date" }
    ];
  }
  return [];
});

// 重置动态表单与上传
function resetExtra() {
  Object.keys(detailsForm).forEach(k => delete (detailsForm as any)[k]);
  uploadedUrls.value = [];
  uploadFileList.value = [];
  // 重置多人分配
  isMultiProject.value = false;
  allocationList.splice(0, allocationList.length);
  allocationEvidenceUploadFiles.value = [];
  allocationEvidenceUrls.value = [];
}

// 监听分类变化，重置动态项
watch(() => formData.subCategory, () => resetExtra());
watch(() => formData.itemCategory, () => resetExtra());

// 监听是否多人参与切换
watch(() => isMultiProject.value, (v) => {
  if (!v) {
    allocationList.splice(0, allocationList.length);
    allocationEvidenceUploadFiles.value = [];
    allocationEvidenceUrls.value = [];
  } else {
    ensureLeaderRow();
  }
});

const statusList = userStore.dictionaryMap["common.status"];

const rules: FormRules = {
  assessmentYear: [
    {
      required: true,
      message: "考核年度不能为空"
    }
  ],
  mainCategory: [
    {
      required: true,
      message: "主类别不能为空"
    }
  ],
  subCategory: [
    {
      required: true,
      message: "子类别不能为空"
    }
  ],
  itemCategory: [
    {
      required: true,
      message: "项目类别不能为空"
    }
  ],
  title: [
    {
      required: true,
      message: "标题不能为空"
    }
  ],
  userReportedScore: [
    {
      required: true,
      message: "申请分数不能为空"
    }
  ]
};
const formRef = ref<FormInstance>();
async function handleOpened() {
  if (props.row) {
    Object.assign(formData, props.row);
    // 等待 Vue 响应式更新完成，确保 dynamicFields 计算属性已更新
    await nextTick();
    // 还原详情
    try {
      const json = props.row.detailsJson;
      if (json) {
        const parsed = JSON.parse(json);
        // 再次等待，确保 dynamicFields 已根据 formData 更新
        await nextTick();
        Object.assign(detailsForm, parsed);
        // 还原是否多人参与（若在 detailsJson 中存储了该标记）
        if (Object.prototype.hasOwnProperty.call(parsed, "isMultiProject")) {
          isMultiProject.value = !!parsed.isMultiProject;
        }
      }
    } catch {}
    // 还原文件
    const files = (props.row.fileList || "").split(";").map(s => s.trim()).filter(Boolean);
    uploadedUrls.value = files;
    uploadFileList.value = files.map((url, idx) => ({ name: `证明材料${idx + 1}`, url, status: "success" }));
    // 还原多人分配（兼容旧格式与新格式，只有当 isMultiProject 不为 false 时才还原）
    await nextTick();
    // 检查 detailsJson 中的 isMultiProject，如果为 false 则不还原多人分配数据
    let shouldRestoreAllocation = true;
    try {
      const json = props.row.detailsJson;
      if (json) {
        const parsed = JSON.parse(json);
        if (Object.prototype.hasOwnProperty.call(parsed, "isMultiProject") && parsed.isMultiProject === false) {
          shouldRestoreAllocation = false;
        }
      }
    } catch {}
    
    if (shouldRestoreAllocation) {
      try {
        const alloc = (props.row as any)?.allocationDetails;
        if (alloc) {
          const parsed = JSON.parse(alloc);
          if (Array.isArray(parsed) && parsed.length) {
            // 旧格式：数组，每条含 userId/score/materials
            isMultiProject.value = true;
            await nextTick();
            allocationList.splice(0, allocationList.length, ...parsed.map((it: any) => ({
              userId: it.userId,
              userLabel: undefined,
              score: it.score
            })));
            // 合并所有行的材料作为共享依据
            const merged: string[] = [];
            parsed.forEach((it: any) => {
              (it.materials || []).forEach((u: string) => { if (u && !merged.includes(u)) merged.push(u); });
            });
            allocationEvidenceUrls.value = merged;
            allocationEvidenceUploadFiles.value = merged.map((url, i) => ({ name: `分配依据${i + 1}` , url, status: "success" }));
          } else if (parsed && typeof parsed === "object") {
            // 新格式：{ materials: string[], items: [{userId,score}] }
            isMultiProject.value = true;
            await nextTick();
            const items = Array.isArray(parsed.items) ? parsed.items : [];
            allocationList.splice(0, allocationList.length, ...items.map((it: any) => ({ userId: it.userId, userLabel: undefined, score: it.score })));
            const mats: string[] = Array.isArray(parsed.materials) ? parsed.materials : [];
            allocationEvidenceUrls.value = mats;
            allocationEvidenceUploadFiles.value = mats.map((url, i) => ({ name: `分配依据${i + 1}` , url, status: "success" }));
          }
        }
      } catch {}
    }
  } else {
    formRef.value?.resetFields();
    resetExtra();
  }
  // 加载全量用户用于本地搜索
  await fetchAllUsersSimple();
  // 如果有多人分配数据，还原用户标签
  if (props.row && isMultiProject.value && allocationList.length > 0) {
    await nextTick();
    allocationList.forEach((item, idx) => {
      if (item.userId) {
        const user = allUsers.value.find(u => u.userId === item.userId);
        if (user) {
          item.userLabel = getUserLabel(user);
        }
      }
    });
  }
  if (isMultiProject.value) {
    await nextTick();
    ensureLeaderRow();
  } else {
    ensureCurrentUserOption();
  }
}

// 自定义上传
async function handleCustomUpload(option: any) {
  const file = option.file as File;
  const fd = new FormData();
  fd.append("file", file);
  try {
    // http 拦截器已处理非0状态为异常，这里拿到的 data 为实际业务数据
    const { data } = await uploadToQiniuApi(fd);
    if (data?.url) {
      // 不直接修改原生 File（其属性只读），将响应交给 on-success 回调处理
      option.onSuccess(data);
    } else {
      option.onError(new Error("上传失败：未返回URL"));
    }
  } catch (e: any) {
    option.onError(e);
  }
}

// 上传类型限制（图片、常见 Office、PDF、文本、压缩包等）
const allowedExtensions = [
  ".jpg", ".jpeg", ".png", ".gif", ".bmp", ".webp",
  ".pdf",
  ".doc", ".docx", ".xls", ".xlsx", ".ppt", ".pptx",
  ".txt", ".csv",
  ".zip", ".rar", ".7z"
];
const acceptUploadTypes = allowedExtensions.join(",");
function beforeUploadValidate(file: File) {
  const name = file.name || "";
  const idx = name.lastIndexOf(".");
  const ext = idx >= 0 ? name.slice(idx).toLowerCase() : "";
  if (!allowedExtensions.includes(ext)) {
    ElMessage.error("仅支持上传以下类型：JPG、JPEG、PNG、GIF、BMP、WEBP、PDF、DOC、DOCX、XLS、XLSX、PPT、PPTX、TXT、CSV、ZIP、RAR、7Z");
    return false;
  }
  return true;
}

// 上传成功：由 element-plus 传入的 file 为 UploadFile，可安全修改其 name/url 用于展示
function handleUploadSuccess(response: any, file: any) {
  if (response?.url) {
    file.url = response.url;
    if (response.fileName) file.name = response.fileName;
    // 记录已上传的URL，供提交与删除使用
    uploadedUrls.value.push(response.url);
  }
}

function handleRemove(file: any) {
  const url = file.url || (file.response && file.response.url);
  if (!url) return;
  uploadedUrls.value = uploadedUrls.value.filter(u => u !== url);
}

// 多人分配 共享依据材料上传回调
function handleAllocEvidenceSuccess(response: any, file: any) {
  if (response?.url) {
    file.url = response.url;
    if (response.fileName) file.name = response.fileName;
    allocationEvidenceUrls.value.push(response.url);
  }
}
function handleAllocEvidenceRemove(file: any) {
  const url = file.url || (file.response && file.response.url);
  if (!url) return;
  allocationEvidenceUrls.value = allocationEvidenceUrls.value.filter(u => u !== url);
}

function onAllocateUserChange(idx: number, userId?: number) {
  if (allocationList[idx]?.fixed) return;
  if (!userId) return;
  // 重复校验
  const dup = allocationList.some((it, i) => i !== idx && it.userId === userId);
  if (dup) {
    ElMessage.error("该用户已在分配列表中");
    allocationList[idx].userId = undefined;
    allocationList[idx].userLabel = undefined;
    return;
  }
  const user = userOptions.value.find(u => u.userId === userId);
  allocationList[idx].userLabel = user ? getUserLabel(user) : undefined;
}

const loading = ref(false);
async function handleConfirm() {
  try {
    // 先校验基础表单
    await formRef.value?.validate();

    // 校验动态字段（全部必填）
    for (const f of dynamicFields.value) {
      const v = (detailsForm as any)[f.key];
      if (v === undefined || v === null || v === "") {
        ElMessage.error(`请完善“${f.label}”信息`);
        return;
      }
    }
    // 校验证明材料（必传）
    if (!uploadedUrls.value.length) {
      ElMessage.error("请上传证明材料（至少1个）");
      return;
    }

    // 如果为多人参与项目，进行分配校验与封装
    if (isMultiProject.value) {
      if (!allocationList.length) {
        ElMessage.error("请添加分配明细");
        return;
      }
      // 当前用户必须在列表中
      const currentId = currentUserId.value;
      if (!currentId) {
        ElMessage.error("无法获取当前用户，请重新登录");
        return;
      }
      const includesSelf = allocationList.some(it => it.userId === currentId);
      if (!includesSelf) {
        ElMessage.error("分配分数时需要添加本人");
        return;
      }
      // 每条校验（用户与分数必填）
      for (let i = 0; i < allocationList.length; i++) {
        const it = allocationList[i];
        if (!it.userId) {
          ElMessage.error(`第 ${i + 1} 条分配未选择用户`);
          return;
        }
        if (it.score === undefined || it.score === null || isNaN(Number(it.score))) {
          ElMessage.error(`第 ${i + 1} 条分配未填写分数`);
          return;
        }
      }
      // 共享依据材料校验
      if (!allocationEvidenceUrls.value.length) {
        ElMessage.error("请上传分配依据材料（至少1个，所有分配共享）");
        return;
      }
      // 总分校验
      const sum = allocationList.reduce((acc, it) => acc + Number(it.score || 0), 0);
      if (sum !== Number(formData.userReportedScore)) {
        ElMessage.error("分配分数之和必须等于申请总分数");
        return;
      }
      // 组装保存的数据（新格式）
      const payload = {
        materials: allocationEvidenceUrls.value,
        items: allocationList.map(it => ({ userId: it.userId, score: Number(it.score) }))
      };
      (formData as any).allocationDetails = JSON.stringify(payload);
    } else {
      (formData as any).allocationDetails = "";
    }

    // 写回details与文件（附带是否多人参与标记）
    const detailsWithFlags = { ...detailsForm } as Record<string, any>;
    detailsWithFlags.isMultiProject = isMultiProject.value;
    (formData as any).detailsJson = JSON.stringify(detailsWithFlags);
    (formData as any).fileList = uploadedUrls.value.join(";");

    // 新增时计算并写入 ownerScore
    if (props.type === "add") {
      let ownerScore = 0;
      if (isMultiProject.value) {
        const currentId = currentUserId.value;
        const selfAlloc = allocationList.find(it => it.userId === currentId);
        ownerScore = Number(selfAlloc?.score || 0);
      } else {
        ownerScore = Number(formData.userReportedScore || 0);
      }
      (formData as any).ownerScore = ownerScore;
    }

    loading.value = true;
    if (props.type === "add") {
      await addSubmissionApi(formData);
    } else if (props.type === "update") {
      await updateSubmissionApi(formData as UpdateSubmissionCommand);
    }
    ElMessage.info("提交成功");
    visible.value = false;
    emits("success");
  } catch (e) {
    console.error(e);
    ElMessage.error((e as Error)?.message || "提交失败");
  } finally {
    loading.value = false;
  }
}
</script>

<template>
  <v-dialog
    show-full-screen
    :fixed-body-height="false"
    use-body-scrolling
    :title="type === 'add' ? '新增绩效上报' : '更新绩效上报'"
    v-model="visible"
    :loading="loading"
    @confirm="handleConfirm"
    @cancel="visible = false"
    @opened="handleOpened"
  >
    <el-form :model="formData" label-width="120px" :rules="rules" ref="formRef">
      <el-form-item prop="assessmentYear" label="考核年度" required inline-message>
        <el-input-number :min="2000" :max="2100" v-model="formData.assessmentYear" />
      </el-form-item>
      <el-form-item prop="mainCategory" label="主类别" required>
        <el-select
          v-model="formData.mainCategory"
          placeholder="请选择主类别"
          style="width: 100%"
        >
          <el-option
            v-for="item in mainCategoryOptions"
            :key="item.value"
            :label="item.label"
            :value="item.value"
          />
        </el-select>
      </el-form-item>
      <el-form-item prop="subCategory" label="子类别" required>
        <el-select
          v-model="formData.subCategory"
          placeholder="请选择子类别"
          :disabled="!formData.mainCategory || formData.mainCategory === '其他工作量'"
          style="width: 100%"
        >
          <el-option
            v-for="item in subCategoryOptions"
            :key="item.value"
            :label="item.label"
            :value="item.value"
          />
        </el-select>
      </el-form-item>
      
      <!-- 工作量计分办法展示 -->
      <el-form-item v-if="currentScoringRule" label="工作量计分办法">
        <el-card shadow="never" class="scoring-rule-card">
          <div class="scoring-rule-content">{{ currentScoringRule }}</div>
        </el-card>
      </el-form-item>
      <el-form-item prop="itemCategory" label="项目类别" required>
        <el-select
          v-model="formData.itemCategory"
          placeholder="请选择项目类别"
          :disabled="!formData.subCategory || (formData.mainCategory === '其他工作量' && formData.subCategory === '其他')"
          style="width: 100%"
        >
          <el-option
            v-for="item in itemCategoryOptions"
            :key="item.value"
            :label="item.label"
            :value="item.value"
          />
        </el-select>
      </el-form-item>
      <el-form-item prop="title" label="标题" required>
        <el-input v-model="formData.title" />
      </el-form-item>
      <div
        v-if="type === 'update' && formData.status === 'REJECTED' && formData.rejectionReason"
        class="rejection-alert"
      >
        <el-alert
          type="error"
          show-icon
          :closable="false"
          title="驳回理由"
          :description="formData.rejectionReason"
        />
      </div>

      <!-- 动态详情表单：随子类别变化 -->
      <template v-if="dynamicFields.length">
        <el-divider>项目详情</el-divider>
        <el-row :gutter="12">
          <el-col :span="12" v-for="field in dynamicFields" :key="field.key">
            <el-form-item :label="field.label" required>
              <template v-if="field.type === 'number'">
                <el-input-number v-model="detailsForm[field.key]" :min="0" style="width: 100%" />
              </template>
              <template v-else-if="field.type === 'date'">
                <el-date-picker v-model="detailsForm[field.key]" type="date" value-format="YYYY-MM-DD" placeholder="选择日期" style="width: 100%" />
              </template>
              <template v-else-if="field.type === 'textarea'">
                <el-input type="textarea" v-model="detailsForm[field.key]" />
              </template>
              <template v-else-if="field.type === 'switch'">
                <el-radio-group v-model="detailsForm[field.key]">
                  <el-radio :label="true">是</el-radio>
                  <el-radio :label="false">否</el-radio>
                </el-radio-group>
              </template>
              <template v-else>
                <el-input v-model="detailsForm[field.key]" />
              </template>
            </el-form-item>
          </el-col>
        </el-row>
      </template>


      <!-- 证明材料（必传，可多文件） -->
      <el-form-item prop="fileList" >
        <template #label>
          <span style="font-weight: 600;">
            <span style="color: var(--el-color-danger); margin-right: 4px;">*</span>证明材料
          </span>
        </template>
        <el-upload
          v-model:file-list="uploadFileList"
          :http-request="handleCustomUpload"
          :before-upload="beforeUploadValidate"
          :accept="acceptUploadTypes"
          :on-success="handleUploadSuccess"
          :on-remove="handleRemove"
          multiple
          list-type="text"
          :limit="20"
        >
          <el-button type="primary">上传证明材料</el-button>
          <template #tip>
            <div class="el-upload__tip">必填，支持多文件上传；仅支持：JPG、JPEG、PNG、PDF、DOC、DOCX、XLS、XLSX、TXT、ZIP、RAR、7Z</div>
          </template>
        </el-upload>
      </el-form-item>

      <el-form-item prop="userReportedScore" label="申请总分数" required>
        <el-input-number :min="0" v-model="formData.userReportedScore" />
      </el-form-item>

      <!-- 是否多人参与（始终显示） -->
      <el-form-item label="是否多人参与">
        <el-radio-group v-model="isMultiProject">
          <el-radio :label="false">否</el-radio>
          <el-radio :label="true">是</el-radio>
        </el-radio-group>
      </el-form-item>

      <template v-if="isMultiProject">
        <el-alert type="info" show-icon :closable="false" title="分配分数时需要添加本人；分配总分必须等于申请总分；分配依据材料只需上传一份（共享）。" />
        <div style="height: 10px"></div>
        <el-form-item>
          <template #label>
            <span style="font-weight: 600;">
              <span style="color: var(--el-color-danger); margin-right: 4px;">*</span>上传分配依据
            </span>
          </template>
          <el-upload
            v-model:file-list="allocationEvidenceUploadFiles"
            :http-request="handleCustomUpload"
            :before-upload="beforeUploadValidate"
            :accept="acceptUploadTypes"
            :on-success="handleAllocEvidenceSuccess"
            :on-remove="handleAllocEvidenceRemove"
            multiple
            list-type="text"
            :limit="20"
          >
            <el-button>上传依据材料</el-button>
            <template #tip>
              <div class="el-upload__tip">必填，支持多文件上传；仅支持：JPG、JPEG、PNG、PDF、DOC、DOCX、XLS、XLSX、TXT、ZIP、RAR、7Z
              </div>
            </template>
          </el-upload>
        </el-form-item>
        <div style="height: 10px"></div>

        <div
  v-for="(row, idx) in allocationList"
  :key="idx"
  style="border: 1px solid var(--el-border-color); padding: 12px; border-radius: 6px; margin-bottom: 12px;"
>
  <el-row class="alloc-row" :gutter="12">
    <el-col :span="12" class="alloc-cell">
      <el-form-item :label="idx === 0 ? '项目负责人' : `项目成员${idx+1}`" required :label-width="120">
        <el-select
          v-model="row.userId"
          filterable
          remote
          reserve-keyword
          :placeholder="row.fixed ? (row.userLabel || '当前用户') : '搜索并选择用户'"
          :remote-method="remoteSearchUsers"
          style="width:100%"
          :disabled="row.fixed"
          @change="onAllocateUserChange(idx, row.userId)"
        >
          <el-option
            v-for="u in userOptions"
            :key="u.userId"
            :label="getUserLabel(u)"
            :value="u.userId"
          />
        </el-select>
      </el-form-item>
    </el-col>

    <el-col :span="8" class="alloc-cell">
      <el-form-item label="分配分数" required :label-width="90">
        <el-input-number :min="0" v-model="row.score" style="width:100%" />
      </el-form-item>
    </el-col>

    <el-col :span="4" class="alloc-actions">
      <el-button v-if="!row.fixed" type="danger" @click="removeAllocationRow(idx)">删除</el-button>
      <span v-else class="alloc-fixed-hint">负责人固定</span>
    </el-col>
  </el-row>

</div>
<div style="height: 10px"></div>

<el-button type="primary" @click="addAllocationRow">新增分配</el-button>

      </template>
      <div style="height: 20px"></div>

    </el-form>
  </v-dialog>
</template>


<style scoped>
/* 为表单项增加底部间距 */
:deep(.el-form-item) {
  margin-bottom: 22px;
}

/* 特殊处理动态表单项，减少间距 */
:deep(.el-row .el-form-item) {
  margin-bottom: 18px;
}

/* 为分割线增加上下间距 */
:deep(.el-divider) {
  margin: 24px 0;
}

/* 解决label过长时自动增加间隙 */
:deep(.el-row .el-form-item .el-form-item__label) {
  /* 允许label换行 */
  white-space: normal;
  /* 设置行高，确保换行时有足够的行间距 */
  line-height: 1.5;
  /* 设置label的最小高度，确保换行时有足够的间隙 */
  min-height: 40px;
  /* 垂直居中对齐 */
  display: flex;
  align-items: center;
}

/* 特别处理switch类型的label，因为它们通常较短 */
:deep(.el-row .el-form-item .el-form-item__label:has(.el-switch)) {
  min-height: 20px;
}

  /* 分配行操作列对齐 */
  .alloc-actions {
    display: flex;
    align-items: center;
    justify-content: flex-start;
    height: 100%;
  }
  .alloc-fixed-hint {
    color: var(--el-text-color-secondary);
    font-size: 13px;
  }
  /* 分配行整体开启flex并垂直居中 */
.alloc-row {
  display: flex;
  align-items: center;
}

.rejection-alert {
  padding-left: 120px;
  margin-bottom: 22px;
}

/* 三列都用flex，让内部内容沿交叉轴居中 */
.alloc-cell,
.alloc-actions {
  display: flex;
  align-items: center;
  height: 100%;
}

/* Element Plus 的表单项默认 align-items:flex-start；在分配行里改成居中 */
:deep(.alloc-cell .el-form-item) {
  margin-bottom: 0;          /* 避免不同高度造成基线错位 */
  align-items: center;       /* 关键：让 label+content 垂直居中 */
}

/* 再把 label 和 content 都设为 flex 居中，防止多行label造成偏移 */
:deep(.alloc-cell .el-form-item__label),
:deep(.alloc-cell .el-form-item__content) {
  display: flex;
  align-items: center;
}

/* 如果你前面全局把 label 设了较大的最小高度，这里在分配行内收窄一下，避免抬高行高 */
:deep(.alloc-row .el-form-item .el-form-item__label) {
  min-height: auto;
  line-height: 1.2;
}

/* 计分办法卡片样式 */
.scoring-rule-card {
  background-color: var(--el-fill-color-extra-light);
  border: 1px solid var(--el-border-color-lighter);
}

.scoring-rule-content {
  white-space: pre-wrap;
  line-height: 1.8;
  color: var(--el-text-color-primary);
  font-size: 14px;
  padding: 8px 0;
}

</style>
